package com.AUI
{
	import com.AUI.define.style.*;
	import com.AUI.events.*;
	
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import flash.utils.*;
	/**
	 * @eventType com.AUI.events.AGlobalEvent.SKIN_
	 */
	[Event(name="skin_", type="com.AUI.events.AGlobalEvent")]
	/**
	 * AUI Component,it provides all base features of UI component.
	 * @author HuangMinPing
	 * @site www.AminLab.com
	 */
	public class AComponent extends AComponentBase
	{
		/**
		 * Element name of the component.
		 */
		public var ename:String;
		/**
		 * Id name of the component.
		 */
		public var idName:String;
		/**
		 * Class name of the component.
		 */
		public var className:String;
		/**
		 * Style.
		 * @see #updateStyle()
		 */
		public var style:AComponentStyle = new AComponentStyle;
		/**
		 * Component depth,it decide SKIN event update order.
		 * @see #skinnable
		 * @see #event:skin_
		 */
		protected var depth:int = 0;
		/**
		 * Hover flag.
		 */
		private var _hover:Boolean = false;
		/**
		 * Active flag.
		 */
		private var _active:Boolean = false;
		/**
		 * Checked flag.
		 */
		private var _checked:Boolean = false;
		/**
		 * Disabled flag.
		 */
		private var _disabled:Boolean = false;
		/**
		 * Constructor.
		 */
		public function AComponent()
		{
			// init attributes
			ename = AUIPrivate.getPreSelectorName() || String(getQualifiedClassName(this).split('::')[1]).toLocaleLowerCase();
			// init events
			addEventListener(MouseEvent.ROLL_OVER,onRollOver);
			addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown);
			addEventListener(MouseEvent.CLICK,onClick);
			addEventListener(MouseEvent.ROLL_OUT,onRollOut);
			
			/**************** INITCOMPLETE ****************/
			Object(this).constructor == AComponent && initComplete();
		}
		/**
		 * Call it when the component has initialize complete.
		 */
		protected function initComplete():void
		{
			style.mix(AUIGlobal.currentCss.getStyle(ename));
			updateDrawStyle();
			updateBoxModel();
		}
		/**
		 * Indicates whether the component can accept user interaction.
		 * <p>If exsit correlative pseudo-class,then will mix it into current style.</p>
		 * @see com.AUI.AStyle#disabled
		 */
		public function set disabled(value:Boolean):void
		{
			if(this.disabled == value)
			{
				return;
			}
			_disabled = value;
			mouseChildren = mouseEnabled = !value;
			updateStyle();
		}
		public function get disabled():Boolean
		{
			return _disabled;
		}
		/**
		 * Indicates whether the component is checked.
		 * <p>If exsit correlative pseudo-class,then will mix it into current style.</p>
		 * @see com.AUI.AStyle#checked
		 */
		public function set checked(value:Boolean):void
		{
			if(this.checked == value)
			{
				return;
			}
			_checked = value;
			updateStyle();
		}
		public function get checked():Boolean
		{
			return _checked;
		}
		/**
		 * Get or set the value of the component.
		 */
		public function set value(variable:*):void
		{
		}
		public function get value():*
		{
		}
		/**
		 * Called when MouseEvent.ROLL_OVER event has been dispatched on component.
		 */
		protected function onRollOver(e:MouseEvent):void
		{
			if(checkPseudoStyle(':hover') == false)
			{
				return;
			}
			_hover = true;
			updateStyle();
		}
		/**
		 * Called when MouseEvent.MOUSE_DOWN event has been dispatched on component.
		 */
		protected function onMouseDown(e:MouseEvent):void
		{
			if(checkPseudoStyle(':active') == false)
			{
				return;
			}
			_active = true;
			updateStyle();
		}
		/**
		 * Called when MouseEvent.CLICK event has been dispatched on component.
		 * @param e MouseEvent object
		 */
		protected function onClick(e:MouseEvent):void
		{
			if(_active == false)
			{
				return;
			}
			_active = false;
			updateStyle();
		}
		/**
		 * Called when MouseEvent.ROLL_OUT event has been dispatched on component.
		 * @param e MouseEvent object
		 */
		protected function onRollOut(e:MouseEvent):void
		{
			if(_hover == false && _active == false)
			{
				return;
			}
			_hover  = false;
			_active = false;
			updateStyle();
		}
		/**
		 * Call it to update style of the component.
		 */
		public function updateStyle():void
		{
			updateDrawStyle();
			updateBoxModel();
		}
		/**
		 * Call it to update draw style of the component
		 */
		protected function updateDrawStyle():void
		{
			// 1.clone nature styles
			style.cloneTo(drawStyle);
			// 2.mix pseudo class.
			var css:ACss = AUIGlobal.currentCss;
			var pc1:Vector.<ACssStyleAttr>;
			var pc2:Vector.<ACssStyleAttr>;
			var pc3:Vector.<ACssStyleAttr>;
			// enabled,disabled 2 status render.
			if(_disabled)
			{
				pc1 = css.getStyle(ename			+':disabled');
				pc2 = css.getStyle('#'+idName		+':disabled');
				pc3 = css.getStyle('.'+className	+':disabled');
				pc1 && drawStyle.mix(pc1);
				pc2 && drawStyle.mix(pc2);
				pc3 && drawStyle.mix(pc3);
			}
			else
			{
				if(_hover)
				{
					pc1 = css.getStyle(ename			+':hover');
					pc2 = css.getStyle('#'+idName		+':hover');
					pc3 = css.getStyle('.'+className	+':hover');
					pc1 && drawStyle.mix(pc1);
					pc2 && drawStyle.mix(pc2);
					pc3 && drawStyle.mix(pc3);
				}
				if(_active)
				{
					pc1 = css.getStyle(ename			+':active');
					pc2 = css.getStyle('#'+idName		+':active');
					pc3 = css.getStyle('.'+className	+':active');
					pc1 && drawStyle.mix(pc1);
					pc2 && drawStyle.mix(pc2);
					pc3 && drawStyle.mix(pc3);
				}
			}
			// plus checked status.
			if(_checked)
			{
				pc1 = css.getStyle(ename			+':checked');
				pc2 = css.getStyle('#'+idName		+':checked');
				pc3 = css.getStyle('.'+className	+':checked');
				pc1 && drawStyle.mix(pc1);
				pc2 && drawStyle.mix(pc2);
				pc3 && drawStyle.mix(pc3);
			}
		}
		/**
		 * Check pseudo class whether exist.
		 */
		private function checkPseudoStyle(name:String):Boolean
		{
			var css:ACss = AUIGlobal.currentCss;
			var pc1:Vector.<ACssStyleAttr>;
			var pc2:Vector.<ACssStyleAttr>;
			var pc3:Vector.<ACssStyleAttr>;
			pc1 = css.getStyle(ename		 + name);
			pc2 = css.getStyle('#'+idName	 + name);
			pc3 = css.getStyle('.'+className + name);
			return pc1 || pc2 || pc3;
		}
		/**
		 * [can-read] Component width.when set,the component will be adjust content box width to fit its this new width.
		 * asdoc's problem so that the doc show write-only,actually it can read.
		 */
		override public function set width(value:Number):void
		{
			if(width == value){ return; }
			style.content.width.type   = DIM_TYPE.PX;
			style.content.width.value  = value - (drawStyle.margin.left + drawStyle.margin.right + drawStyle.border.left.width + drawStyle.border.right.width + drawStyle.padding.left + drawStyle.padding.right);
			this.updateStyle();
		}
		override public function get width():Number
		{
			return boxModel.margin.width;
		}
		/**
		 * [can-read] Component height.when set,the component will be adjust content box height to fit its this new height.
		 * asdoc's problem so that the doc show write-only,actually it can read
		 */
		override public function set height(value:Number):void
		{
			if(height == value){ return; }
			style.content.height.type  = DIM_TYPE.PX;
			style.content.height.value = value - (drawStyle.margin.top + drawStyle.margin.bottom + drawStyle.border.top.width + drawStyle.border.bottom.width + drawStyle.padding.top + drawStyle.padding.bottom);
			this.updateStyle();
		}
		override public function get height():Number
		{
			return boxModel.margin.height;
		}
		/**
		 * Set component size.when set,the component will be adjust content box size to fit its this this new size.
		 */
		public function setSize(width:Number,height:Number):void
		{
			style.content.width.type   = DIM_TYPE.PX;
			style.content.height.type  = DIM_TYPE.PX;
			style.content.width.value  = width  - (drawStyle.margin.left + drawStyle.margin.right + drawStyle.border.left.width + drawStyle.border.right.width + drawStyle.padding.left + drawStyle.padding.right);
			style.content.height.value = height - (drawStyle.margin.top + drawStyle.margin.bottom + drawStyle.border.top.width + drawStyle.border.bottom.width + drawStyle.padding.top + drawStyle.padding.bottom);
			this.updateStyle();
		}
	}
}